from fastapi import FastAPI, Depends, Security
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security.api_key import APIKeyHeader, APIKey
from fastapi import HTTPException, status
import logging
import os

from .database.mongodb import connect_to_mongo, close_mongo_connection
from .routers import db_info_setting, auth
from .routers.task_data_sync import setting as task_data_sync_setting
from .routers.task_data_sync import execution_log as task_data_execution_log
from .middleware.api_key_auth import APIKeyMiddleware, API_KEY, jwt_bearer
from .utils.swagger_utils import setup_swagger_ui
from .models.task_data_sync.scheduler import start_scheduler, stop_scheduler, scheduler

# 配置日志级别
logging_level = os.getenv("LOGGING_LEVEL", "INFO").upper()
logging.basicConfig(
    level=getattr(logging, logging_level),
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 创建API密钥头部验证
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)

app = FastAPI(
    title="DBCompareX API",
    description="数据比对的API系统",
    version="0.1.0",
    # 添加Swagger UI参数，保持授权状态
    openapi_tags=[
        {"name": "用户认证", "description": "用户认证和管理相关接口"},
        {"name": "数据库配置设置", "description": "数据库连接配置相关接口"},
        {"name": "数据同步任务", "description": "数据同步任务相关接口"},
        {"name": "执行日志和对比结果", "description": "执行日志和对比结果相关接口"}
    ],
    swagger_ui_parameters={"persistAuthorization": True},
)

# 配置Swagger UI，添加API密钥授权功能
setup_swagger_ui(app)

# 配置CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 在生产环境中应调整为特定源
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 添加API密钥验证中间件
app.add_middleware(APIKeyMiddleware)

# 注册数据库连接和任务调度器启动事件处理器
@app.on_event("startup")
async def startup_db_client():
    logger.info("应用启动：初始化数据库连接和任务调度器")
    try:
        # 连接MongoDB
        await connect_to_mongo()
        logger.info("MongoDB连接成功")
        
        # 启动任务调度器
        await start_scheduler()
        scheduler_status = scheduler.get_scheduler_status()
        logger.info(f"任务调度器启动成功: {scheduler_status}")
        
        # 打印所有注册的任务
        jobs = scheduler.list_all_jobs()
        if jobs:
            logger.info(f"已注册的定时任务: {len(jobs)} 个")
            for job in jobs:
                logger.info(f"任务ID: {job['id']}, 下次执行时间: {job['next_run_time']}")
        else:
            logger.warning("没有找到任何定时任务")
        
        # 在启动时打印生成的API密钥，方便开发调试
        logger.info(f"当前API密钥: {API_KEY}")
        logger.info(f"请在API请求头中添加 X-API-Key: {API_KEY}")
    except Exception as e:
        logger.error(f"应用启动过程中发生错误: {str(e)}", exc_info=True)
        # 在生产环境中，可以选择继续运行而不是抛出异常
        # 如果是关键服务，可以在此抛出异常使应用终止
        # raise e

@app.on_event("shutdown")
async def shutdown_db_client():
    logger.info("应用关闭：清理资源")
    try:
        # 停止任务调度器
        stop_scheduler()
        logger.info("任务调度器已停止")
        
        # 关闭数据库连接
        await close_mongo_connection()
        logger.info("MongoDB连接已关闭")
    except Exception as e:
        logger.error(f"应用关闭过程中发生错误: {str(e)}", exc_info=True)

# 包含路由
app.include_router(auth.router, prefix="/api", tags=["用户认证"])
app.include_router(db_info_setting.router, prefix="/api", tags=["数据库配置设置"])
app.include_router(task_data_sync_setting.router, prefix="/api", tags=["数据同步任务"])
app.include_router(task_data_execution_log.router, prefix="/api", tags=["执行日志和对比结果"])

# 健康检查和测试端点
@app.get("/")
async def root():
    return {"message": "欢迎使用DBCompareX API"}

@app.get("/api/health")
async def health_check():
    """健康检查接口，返回应用状态信息"""
    scheduler_status = scheduler.get_scheduler_status()
    jobs = scheduler.list_all_jobs()
    
    return {
        "status": "ok",
        "scheduler": {
            "running": scheduler_status["running"],
            "jobs_count": scheduler_status["job_count"],
            "jobs": jobs
        }
    }

# 添加需要登录验证的示例接口
@app.get("/api/user-info")
async def get_user_info(payload: dict = Depends(jwt_bearer)):
    """获取当前登录用户信息，需要JWT认证"""
    return {
        "user_id": payload.get("sub"),
        "username": payload.get("username"),
        "role": payload.get("role")
    }